//
//  OnlineStatementViewController.swift
//  ezyform
//
//  Created by Moennig Q on 11/8/2022.
//  Copyright © 2022 Client.Solution Pty Ltd. All rights reserved.
//

import UIKit
import WebKit
import AVFoundation
import CoreLocation
//和H5约定的参数
enum WebViewConvention: String {
    case event = "event"
    case webViewEvent = "WebViewEvent"
    case logger = "logger"
}
//和js交互的参数
enum WebViewJSEvent: String {
    case getPvddetail = "getpvddetail"//
    case capture = "capture"
    case none = ""
}
class OnlineStatementViewController: BaseViewController {
    private var webEventJSType: WebViewJSEvent = .none
    private var selfieKey: String = ""
    private var statementType: SignatureType = .None
    private var clearWebiewCacheFlag: Bool = false//是否清除Webview的网页缓存和localStorage
    //前置摄像头拍照
    var session: AVCaptureSession?
    var output: AVCapturePhotoOutput?
    var customView: OnlineStatementView!
    //参数statementType协议类型，只用到installer，designer，owner
    init(statementType: SignatureType, clearWebiewCacheFlag: Bool = false) {
        super.init(nibName: nil, bundle: nil)
        self.statementType = statementType
        self.clearWebiewCacheFlag = clearWebiewCacheFlag
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        self.initUI()
        self.loadStatement()
    }
    
    func initUI(){
        self.customView = OnlineStatementView()
        self.customView.setTitleInfo("")
        self.customView.initWebView(vc: self)
        self.view = self.customView
        
        customView.withoutNetworkView.retryBtn.addTarget(self, action: #selector(retryBtnClick), for: UIControl.Event.touchUpInside)
    }
    func loadStatement(){
        let urlStr = self.getAgreenmentsInfo()
        if urlStr == "" {
            Tool().showAlertViewWithOneBtn(message: "\(self.statementType.rawValue) Online statement url is null")
        }
        if urlStr.contains("http") {//在线
            guard let requestUrl = URL(string: urlStr) else {
                return
            }
            var request = URLRequest(url: requestUrl)
            request.cachePolicy = .reloadIgnoringLocalCacheData//忽略本地缓存
            self.customView.webView.load(request)
        }else{//local
            guard let url = Bundle.main.url(forResource: urlStr, withExtension: "html") else {
                return
            }
            self.customView.webView.loadFileURL(url, allowingReadAccessTo: Bundle.main.bundleURL)
        }
    }
    @objc func retryBtnClick(){
        if self.customView.webView.url != nil{
            self.customView.webView.reload()
        }else{
            self.loadStatement()
        }
    }
    private func getAgreenmentsInfo() -> String {
        var urlStr: String = ""
        if JobDetailModelHelper.shared.jobDetailModel.solar_water_heater{//热水器
            switch statementType {
            case .Owner:
                urlStr = JobDetailModelHelper.shared.jobDetailModel.agreenments.ownerStatementUrlStr
            default:
                break
            }
        }else{
            if JobDetailModelHelper.shared.jobDetailModel.is_new_stc_form {//新协议
                switch statementType {
                case .Installer:
                    urlStr = JobDetailModelHelper.shared.jobDetailModel.agreenments.installerStatementUrlStr
                case .Designer:
                    urlStr = JobDetailModelHelper.shared.jobDetailModel.agreenments.designerStatementUrlStr
                case .Owner:
                    urlStr = JobDetailModelHelper.shared.jobDetailModel.agreenments.ownerStatementUrlStr
                default:
                    break
                }
                
            }else{//老协议
                switch statementType {
                case .Installer:
                    urlStr = JobDetailModelHelper.shared.jobDetailModel.agreenments.installerOldStatementUrlStr
                case .Owner:
                    urlStr = JobDetailModelHelper.shared.jobDetailModel.agreenments.ownerOldStatementUrlStr
                default:
                    break
                }
            }
        }
        
        return urlStr
    }
    // MARK: - 拍照
    func getDevice(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
        let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: position)
        let devices = deviceDiscoverySession.devices
        if devices.count > 0 {
            return devices[0]
        }
        return nil
    }
    func setupInputOutput(){
        if let camera = getDevice(position: .front) {
            do {
                self.session = AVCaptureSession()
                self.output = AVCapturePhotoOutput()
                guard let _ = self.session,let _ = output  else {
                    return
                }
                self.session!.beginConfiguration()
                //如果session包括AVCapturePhotoOutput对象，session会自动尝试启用wide-color，有些设备(iPad)并不支持activeFormat.supportedColorSpaces，这是个AVCaptureSession的坑
                self.session!.automaticallyConfiguresCaptureDeviceForWideColor = false
                let input = try AVCaptureDeviceInput(device: camera)
                if self.session!.canAddInput(input){
                    self.session!.addInput(input)
                }
                output!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg] )], completionHandler: nil)
                session!.sessionPreset = .photo
                if session!.canAddOutput(output!){
                    session!.addOutput(output!)
                }
                self.session!.commitConfiguration()
                DispatchQueue.global(qos: .background).async {
                    self.session!.startRunning()
                }
                
            }catch{
                print(error)
            }
        }
    }
    
    // MARK:- 保存 保存自拍照
    private func saveSelfie(_ imageData: Data? =  nil) {
        if let data = imageData{//拍照成功
            let normalData = MediaUtil().normalizedImage(data)
            let originImageData = MediaUtil().resetSizeOfImageData(source_image: UIImage(data: normalData),maxSize: 100)
            APPConfig.loginInfo.signatureInfoModel.onlineStatementPhotoParams[self.selfieKey] = originImageData
        }
        //拍照后，调用JS继续下一步
        self.customView.webView.evaluateJavaScript("captureSuccess();")
    }
    
    private func toSignatureVC() {
        if JobDetailModelHelper.shared.jobDetailModel.is_new_stc_form {//新协议
            switch self.statementType {
            case .Installer:
                let vc = InstallerSignForNewStcFormVC()
                self.navigationController?.pushViewController(vc, animated: false)
            case .Designer:
                let vc = DesignerSignForNewStcFormVC()
                self.navigationController?.pushViewController(vc, animated: false)
            case .Owner:
                let vc = OwnerSignForNewStcFormVC()
                self.navigationController?.pushViewController(vc, animated: false)
            default:
                break
            }
        }else{//有老协议的签名：包括installer或者owner
            let vc = PVDSignagtureViewController()
            vc.signatureType = self.statementType
            self.navigationController?.pushViewController(vc, animated: false)
        }
        
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.setNavigationBarHidden(true, animated: false)
        if let _ = self.session {
            DispatchQueue.global(qos: .background).async {
                self.session!.startRunning()
            }
        }
    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let _ = self.session {
            self.session!.stopRunning()
        }
    }
    deinit {
        //尽可能释放无用的内存
        self.session = nil
        self.output = nil
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        DebugLog("\(self) didReceiveMemoryWarning")
    }
}
extension OnlineStatementViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        switch WebViewConvention(rawValue: message.name)  {
        case .logger://调试打印js中的console.log(信息)
            DebugLog(message.body)
        case .event://约定的event，body中会有一个event参数
            if let dic = message.body as? NSDictionary {
                if let event = dic.object(forKey: "event") as? String {
                    
                    switch WebViewJSEvent(rawValue: event.lowercased()) {
                    case .getPvddetail:
                        let jsonData = self.convertDictionaryToString(dict: APPConfig.loginInfo.signatureInfoModel.onlineStatementPVDDetail)
                        if jsonData.count > 0 {
                            let initData = String(format: "init_pvd_detail(%@);", jsonData)
                            self.customView.webView.evaluateJavaScript(initData)
                        }
                    case .capture://需要拍照
                        
                        if let data = dic.object(forKey: "key") as? String{
                            self.selfieKey = data
                        }
                        let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
                        if authStatus == .authorized { /****已授权，可以打开相机且installer或owner才自拍****/
                            ModelViewUtil.shared.showLoadingView("Processing")
                            //启动设备
                            setupInputOutput()
                            let delay = Double(3) * Double(NSEC_PER_SEC)
                            let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC)
                            DispatchQueue.main.asyncAfter(deadline: time) {
                                
                                //延迟两秒再拍照，防止图片背景黑的问题
                                if let _ = self.output,let _ = self.session {
                                    let settings = AVCapturePhotoSettings()
                                    self.output!.capturePhoto(with: settings, delegate: self)
                                }else{
                                    ModelViewUtil.shared.hideLoadingView()
                                    self.saveSelfie()
                                }
                            }
                        }
                    default:
                        break
                    }
                }
            }
        case .webViewEvent:
            if let dic = message.body as? [String: Any] {//
                //1.statement_input_param_all参数以最后传过来的为准
                if let newParamsJsonStr = dic["statement_input_param_all"] as? String {
                    APPConfig.loginInfo.signatureInfoModel.onlineStatementParams["statement_input_param_all"] = newParamsJsonStr
                }
                //2.交互参数
                APPConfig.loginInfo.signatureInfoModel.onlineStatementParams.merge(dic) { first, _ in
                    return first
                }
                self.toSignatureVC()
            }
        default:
            break
        }
    }
    
}
extension OnlineStatementViewController: WKNavigationDelegate, WKUIDelegate{
    //WKNavigationDelegate
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.evaluateJavaScript("document.title", completionHandler: { [weak self] (title, error) in
            guard let self = self else { return }
            self.customView.setTitleInfo((title as? String ?? ""))
        })
        
        //清楚js的localstorage, 在每个签名的入口只清理一次
        if self.clearWebiewCacheFlag {//
            //清楚Html网页缓存
            self.clearWebiewCache()
            self.clearWebiewCacheFlag = false
        }
        self.customView.showViewAfterLoad(true)
    }
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        if let err = error as? URLError,err.errorCode == URLError.cancelled.rawValue {//-999表示当前请求被cancelled取消，然后被重定向到另外一个html了; designer_index.html就是这样的问题，解决方法忽略此问题直接return即可
            return
        }else{//其他错误显示加载失败即可
            self.customView.showViewAfterLoad(false)
        }
        
    }
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
//        print(error.localizedDescription)
        self.customView.showViewAfterLoad(false)
    }
    //此代理方法必须实现，否则假网络时不会调用didFailProvisionalNavigation
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        decisionHandler(WKNavigationActionPolicy.allow)
    }
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        if let response = navigationResponse.response as? HTTPURLResponse, response.statusCode == 204{
            self.customView.showViewAfterLoad(false)
            decisionHandler(WKNavigationResponsePolicy.cancel)
        }else{
            decisionHandler(WKNavigationResponsePolicy.allow)
        }
        
    }
    //iOS解决WKWebView下alert(),confirm(),prompt()不执行方法
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void){
        Tool().showAlertViewWithOneBtn(message: message)
    }
    
    private func convertDictionaryToString(dict: [String: Any]) -> String {
      var result:String = ""
      do {
        //如果设置options为JSONSerialization.WritingOptions.prettyPrinted，则打印格式更好阅读
        let jsonData = try JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions.init(rawValue: 0))
        if let JSONString = String(data: jsonData, encoding: String.Encoding.utf8) {
            result = JSONString.trimmingCharacters(in: .whitespacesAndNewlines)
        }
      } catch {
        result = ""
      }
      return result
    }
    private func clearWebiewCache(){
        
        WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })
        //清楚localStorage
        self.customView.webView.evaluateJavaScript("window.localStorage.clear();",completionHandler: nil)
    }
    //暂时没有y加载服务器协议到本地
    private func loadStatementToLocal(_ urlStr: String){
        guard let myURL = URL(string: urlStr) else {
            print("Error: \(urlStr) doesn't seem to be a valid URL")
            return
        }
        do {
            let myHTMLString = try String(contentsOf: myURL, encoding: .ascii)
            self.saveHTMLToLocal(myHTMLString)
            
        } catch let error {
            print("Error: \(error)")
        }
    }
    private func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
    private func saveHTMLToLocal(_ htmlString: String){
        

        let filename = getDocumentsDirectory().appendingPathComponent("agreements/installer/installer_index.html")

        do {
            try htmlString.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
        } catch {
            print("保存失败")
        }
    }
}
extension OnlineStatementViewController: AVCapturePhotoCaptureDelegate{
    @available(iOS 11.0, *)
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        //自拍完要关闭processing
        ModelViewUtil.shared.hideLoadingView()
        if let _ = self.session{
            self.session!.stopRunning()
        }
        
        if let _ = error{
            let errMsg = "\(self.statementType.rawValue) click Agree Button and can not take selfi, the reason: " + error!.localizedDescription
            AppLogHelper.shared.sendErrorLog(errMsg, errorType: ErrorType.Signature)
            self.saveSelfie()
        }else{
            if let imageData = photo.fileDataRepresentation() {
                self.saveSelfie(imageData)
                
            }else{
                let errMsg = "\(self.statementType.rawValue) click Agree Button and can not take selfi, the reason: photo.fileDataRepresentation() not working"
                AppLogHelper.shared.sendErrorLog(errMsg, errorType: ErrorType.Signature)
                self.saveSelfie()
            }
        }
    }
}

